"""
""" quickly execution for python/bash scripts
"""
  let g:sd_gcc_temp_dir = ' -o /tmp/tmp_c.bin -lm -lpthread && /tmp/tmp_c.bin'

"""
""" linux only, yank to local file, to achieve cross vim instance paste
"""
  let g:sd_yank_file="/tmp/vim_yank"
  function! Sd_Yank_to_local_file()
    let l:yank_content_64 = system("base64 -w 0 ", getreg('"'))
    exe ':redir! >'. g:sd_yank_file.'|silent echo l:yank_content_64|redir END'
  endfunction

  function! Sd_paste_from_local_file() abort
    let l:yank_content = system("base64 -d " . g:sd_yank_file)
    call setreg('t', l:yank_content)
    exe "put t |normal gpgt"
  endfunction

  nnoremap <silent> <leader>y "tyy:call Sd_Yank_to_local_file()<CR>
  vnoremap <silent> <leader>y "ty:call Sd_Yank_to_local_file()<CR>
  nnoremap <silent> <leader>p :call Sd_paste_from_local_file()<CR>

"""
""" quickly open a temporay file
"""
  let g:sd_tempfile_dir = "/tmp/"

  function! Sd_complete_list_tmp_dir(ArgLead, CmdLine, CursorPos, ...)
    let dir = a:CmdLine
    if dir =~ '^/'
      if dir !~ '/$'
        let dir = dir .. '/'
      endif
      echo dir
      let myList = readdir(dir)
      call map(myList, 'dir .. v:val')
      return myList
    else
      let myList = readdir(g:sd_tempfile_dir)
    endif
    return filter(myList, 'v:val =~ "^'. a:ArgLead .'"')
  endfunction

  function! Sd_complete_list_cwd(ArgLead, CmdLine, CursorPos, ...)
    let myList = readdir(expand('%:p:h'))
    return filter(myList, 'v:val =~ "^'. a:ArgLead .'"')
  endfunction

  function! Sd_quick_openfile(mode)
    if a:mode == 'temp'
      let sd_tempfile = input("temp > ", "", "customlist,Sd_complete_list_tmp_dir")
    else
      let sd_tempfile = input("cwd > ", "", "customlist,Sd_complete_list_cwd")
    endif
    if sd_tempfile =~ '^\s*$' || sd_tempfile =~ ".*\<Esc>.*" || sd_tempfile =~ ".*\<C-C>.*"
      return
    endif
    let sd_match_res = matchstr(sd_tempfile, '^\(/\|\.\.\|\.\)')
    if empty(sd_match_res)
      if a:mode == 'temp'
        let sd_tempfile = g:sd_tempfile_dir . sd_tempfile
      else
        let sd_tempfile = expand("%:p:h") . '/' . sd_tempfile
      endif
    endif
    exe ':vs'
    exe ':edit '. sd_tempfile
  endfunction

  nnoremap <silent> <localleader>f :<c-u>call Sd_quick_openfile('temp')<cr>
  vnoremap <silent> <localleader>f :<c-u>call Sd_quick_openfile('temp')<cr>
  nnoremap <silent> <localleader>F :<c-u>call Sd_quick_openfile('current')<cr>

"""
""" 插入文件头
"""
  if has("win32") || has("win64")
    let g:sd_template_dir = g:sd_vim_dir . '/seadog_files/templates/'
  else
    let g:sd_template_dir = g:sd_vim_dir . '/templates/'
  endif

  function! Sd_insert_template() abort
    if &ft == 'python'
      exe "0read " . g:sd_template_dir . 'head_python'
    elseif &ft == 'c'
      exe "0read " . g:sd_template_dir . 'head_c'
    elseif &ft == 'sh'
      exe "0read " . g:sd_template_dir . 'head_bash'
    elseif &ft == 'go'
      exe "0read " . g:sd_template_dir . 'head_go'
    elseif &ft == 'html'
      exe "0read " . g:sd_template_dir . 'head_html'
    else
      call Sd_insert_template_02()
      return
    endif
    silent! exe "%s~FILENAME~" . expand('%:t')
    silent! exe "%s~DATETIME~" . strftime('%a %Y-%m-%d %H:%M:%S(%z)')
  endfunction

  function! Sd_complete_list_template_dir(ArgLead, CmdLine, CursorPos, ...)
    let myList = readdir(g:sd_template_dir)
    return filter(myList, 'v:val =~ "^'. a:ArgLead .'"')
  endfunction

  function! Sd_insert_template_02() abort
    let t_file = input("template > ", "", "customlist,Sd_complete_list_template_dir")
    if ! empty(t_file)
      exe "0read " . g:sd_template_dir . '/' . t_file
    endif
  endfunction

"""
""" search list file
"""
  let g:sd_search_list = g:sd_vim_data_dir . "/sd-temp-searchlist.txt"

  function! Sd_list_search_result()
    silent! call Sd_close_any_floating_win()
    if &ft == 'sd-search-list'
      let win_count = winnr('$')
      if win_count < 2
        call Sd_echo("to auto jump using searchlist, the total number of window should be greater than 2!")
        return
      endif
      let line_num = substitute(getline('.'), '\s\+.*', '', '')
      silent! exe ':wincmd h|:normal! ' . line_num . 'G'
      silent! normal! zO
      normal! zz
      silent! exe ':wincmd l'
    else
      silent! exe ':w! '. g:sd_search_list
      silent! exe ':vsplit ' .  g:sd_search_list
      let l:search = @/
      silent! exe ':%s/^/\=printf("%-5d  ", line("."))'
      let @/ = l:search
      silent! exe ':v//d'
      " silent! exe ':let _s=@/|:%s/\s\+$//e|:let @/=_s<CR>'
      silent! exe ':w!|setlocal ft=sd-search-list|setlocal hlsearch'
      " let @/ = l:search
      setlocal hlsearch

      " let search = @/
      " silent! exe ':%y'
      " silent! exe ':vsplit ' . g:sd_search_list
      " normal! ggVGp
      " silent! exe ':%s/^/\=printf("%-5d  ", line("."))'
      " let @/ = search
      " silent! exe ':v//d'
      " silent! exe ':let _s=@/|:%s/\s\+$//e|:let @/=_s<CR>'
      " silent! exe ':w!|setlocal ft=sd-search-list|setlocal hlsearch'
      " let @/ = search

      nnoremap <buffer> <silent> <enter> :call Sd_list_search_result()<CR>
      nnoremap <buffer> <silent> qw :bwipeout!<CR>
    endif
  endfunction

  nnoremap <silent> <leader>i :call Sd_list_search_result()<CR>
  vnoremap <silent> <leader>i "oy:let @/=@o<BAR>:call Sd_list_search_result()<CR>

"""
""" list bookmarks
"""
  let g:sd_oldfiles=g:sd_vim_data_dir . "/sd-temp-oldfiles.txt"
  let g:sd_bookmark_file=g:sd_vim_data_dir . "/sd-temp-bookmarks.txt"

  function! Sd_map_fn(k, v)
    return substitute(a:v, '.*\/', '', '')
  endfunction

  function! Sd_list_bookmarks(operation)
    silent! call Sd_close_any_floating_win()
    if &filetype == 'sd-bookmark'
      let current_line = getline('.')
      let m = matchstr(current_line, '^\(-\|_\|\w\|\d\)\+\.vim$')
      if empty(m )
        if ! filereadable(getline('.'))
          call Sd_echo('file not exist!')
          return
        endif
        let target = getline('.')
        let bfnm = bufnr('%')
        normal! gf
        silent! exe ':bwipeout! ' . bfnm
        silent! call  CloseAnyOtherWindow()
        if a:operation == 3
          silent! exe ':%bd|e#|bd#'
        endif
      else
        call  Sd_session_management(current_line)
      endif
    else
      if a:operation == 1 "add bookmark
        let fname = expand('%:p')
        call system("echo " . fname . " >> " . g:sd_bookmark_file)
        if v:shell_error == 0
          echo "add one bookmark successfully!"
        else
          call Sd_echo("failed to add one bookmark!")
        endif
      else "list oldfiles/bookmarks
        let current_dir = expand('%:p:h')
        silent! exe ':vs ' . g:sd_oldfiles
        silent! normal! ggdG
        silent! call setline(1, "###################################################################  book marks  ############")
        silent! exe ':1r ' . g:sd_bookmark_file

        silent! call setline(line('$') + 1,"")
        silent! call setline(line('$') + 1,"###################################################################  session list ###########")
        silent! normal! G
        silent! let sessions = readdir(g:sd_vim_session_dir, {n -> n =~ '\S\.vim$'})
        call filter(sessions, 'v:val !~ "^lastsession"')
        for item in sessions
          call setline(line('$') + 1, item)
        endfor

        " remove some tool-files
        silent! exe ':g`\v[\\/]sd-temp-oldfiles.txt$`d '
        silent! exe ':g`\v[\\/]lastsession(01)?\.vim$`d'
        silent! exe ':g`toggleterm`d'
        silent! exe ':let _s=@/|:%s/\s\+$//e|:let @/=_s<CR>'
        " process symbol '~'
        if has("win32") || has("win64")
          silent! exe  '%s~\/~\\~g'
          silent! exe  ':g/\~/d'
        else
          silent! exe  ':%s`\~`' . $HOME
        endif

        silent! exe ':w|setlocal ft=sd-bookmark syntax=text'
        setlocal syntax=cfg

        nnoremap <buffer> <silent> u :call Sd_list_bookmarks(2)<CR>
        nnoremap <buffer> <silent> U :call Sd_list_bookmarks(3)<CR>
        nnoremap <buffer> <silent> <enter> :call Sd_list_bookmarks(2)<CR>
        nnoremap <buffer> <silent> qw :bwipeout!<CR>
      endif
    endif
  endfunction

  nnoremap <silent> <leader>O :call Sd_list_bookmarks(1)<CR>
  vnoremap <silent> <leader>O <ESC>:call Sd_list_bookmarks(1)<CR>
  nnoremap <silent> <leader>o :call Sd_list_bookmarks(2)<CR>2G
  vnoremap <silent> <leader>o <ESC>:call Sd_list_bookmarks(2)<CR>2G

"""
""" quick-align
"""
  function! Sd_quick_align(direction, mode) abort
    exe ':retab'
    normal! mp
    let l:current_line = line('.')
    if a:direction == 'up'
      let l:step = 'k^'
      let l:target_line = '`<k'
    else
      let l:step = 'j^'
      let l:target_line = '`>j'
    endif
    if a:mode == 'n'
      exe 'normal ' . l:step
      while 1
        if getline('.') =~ '^\s*$'
          exe 'normal ' . l:step
          if (line('.') == 1  || line('.') == line('$')) && getline('.') =~ '^\s*$'
            normal `p
            return
          endif
          continue
        else
          break
        endif
      endwhile
      let l:final_spaces = repeat(' ', col('.')-1)
      exe l:current_line . ':s/^\s*/' . l:final_spaces
    else
      let l:v_start_line_num = line("'<")
      let l:v_end_line_num = line("'>")
      let l:count = l:v_end_line_num
      let l:smallest_line_col  = 888
      while l:count >= l:v_start_line_num
        if getline(l:count) !~ '^\s*$'
          let l:temp =  Sd_get_begin_whitespace(l:count)
          if l:smallest_line_col > l:temp
            let l:smallest_line_col  = l:temp
          endif
        endif
        let l:count -= 1
      endwhile
      let l:leading_spaces = repeat(' ', l:smallest_line_col )
      exe 'normal ' . l:target_line
      while 1
        if getline('.') =~ '^\s*$'
          exe 'normal ' . l:step
          if (line('.') == 1  || line('.') == line('$')) && getline('.') =~ '^\s*$'
            normal `p
            return
          endif
          continue
        else
          normal ^
          break
        endif
      endwhile
      let l:final_spaces = repeat(' ', col('.')-1)
      exe ':' . l:v_start_line_num . ',' . l:v_end_line_num . 's/^' . l:leading_spaces . '/' . l:final_spaces . '/e'
    endif
  endfunction

"""
""" simple format
"""
  function! Sd_simple_format(mode, dot)
    if a:mode == 'n'
      if a:dot == 'y'
        exe ':s`\s\+\(;\|:\|\.\|?\|{\|\!\|\[\|,\)`\1`ge'
        exe ':s`\(;\|\.\|?\|{\|\!\|\[\|,\|:\)`\1 `ge'
      else
        exe ':s`\s\+\(;\|:\|?\|{\|\!\|\[\|,\)`\1`ge'
        exe ':s`\(;\|?\|{\|\!\|\[\|,\|:\)`\1 `ge'
      endif
      " exe ':s`\(\S\)\@<=\s*\(}\|\]\)` \2`ge'
      exe ':s`\(\S\)\@<=\s*\({\|}\|\[\|\]\)` \2`ge'
      exe ':s`\()\|}\|\]\)\((\|{\|\[\)`\1 \2`ge'
      exe ':s`{\s\+{`{{`ge'
      exe ':s`}\s\+}`}}`ge'
      exe ':s`(\s\+(`((`ge'
      exe ':s`)\s\+)`))`ge'
      exe ':s`\[\s\+\[`\[\[`ge'
      exe ':s`\]\s\+\]`\]\]`ge'
      exe ':s`\(\S\)\@<=\s\+` `ge'
      exe ':s`\s\+$``ge'
    else
      normal mp
      let l:v_start_line_num = line("'<")
      let l:v_end_line_num = line("'>")
      exe "normal! `<"
      let l:count = l:v_start_line_num
      while l:count <= l:v_end_line_num
        call Sd_simple_format('n', a:dot)
        exe 'normal! j'
        let l:count = l:count + 1
      endwhile
      normal `p
    endif
    " exe ':set nohls'
  endfunction

"""
""" diffsplit
"""
  function! Sd_diff_toggle(white_space)
    silent! call Sd_close_any_floating_win()
    if a:white_space == 0
      set diffopt=internal,filler,closeoff,internal,algorithm:patience,iwhite,linematch:60
    else
      set diffopt=internal,filler,closeoff,internal,algorithm:patience,linematch:60
    endif
    let l:win_count = winnr('$')
    if l:win_count == 2
      exe ':wincmd h'
      let l:left_diffmark = &diff
      exe ':wincmd l'
      let l:right_diffmark = &diff
      if ! l:left_diffmark && ! l:right_diffmark
        exe ':windo diffthis'
      else
        exe ':windo diffoff'
      endif
    elseif l:win_count == 1 && &diff == 0
      let l:sd_tempfile = input("full path filename > ", "", "file_in_path")
      if l:sd_tempfile =~ '^\s*$' || l:sd_tempfile =~ ".*\<Esc>.*" || l:sd_tempfile =~ ".*\<C-C>.*"
        return
      endif
      if ! filereadable(l:sd_tempfile)
        call Sd_echo("can not open file \'" . l:sd_tempfile . "\'")
        return
      endif
      exe ':vertical diffsplit ' . l:sd_tempfile
    elseif l:win_count == 1 && &diff == 1
      exe ':diffoff'
    else
      call Sd_echo("Unable to complie with, to start diffsplit, make sure there is one or two window(s)")
    endif
  endfunction

  nnoremap <silent> <leader>df :<c-u>call Sd_diff_toggle(1)<CR>
  vnoremap <silent> <leader>df <ESC>:<c-u>call Sd_diff_toggle(1)<CR>
  nnoremap <silent> <leader><leader>df :<c-u>call Sd_diff_toggle(0)<CR>
  vnoremap <silent> <leader><leader>df <ESC>:<c-u>call Sd_diff_toggle(0)<CR>

  nnoremap <silent> <leader>dg :<c-u>diffget<CR>
  nnoremap <silent> <leader>dp :<c-u>diffput<CR>
  " nnoremap <leader>dc :<c-u>windo diffthis<CR>
  " command Showchanges vert new | set bt=nofile | r ++edit # | 0d_ | diffthis | wincmd p | diffthis
  " command Showchanges vert new | set buftype=nofile | read ++edit # | 0d_ | diffthis | wincmd p | diffthis
  " nnoremap <silent> <leader>dc :<c-u>Showchanges<CR><c-w>l

"""
""" quick update vimrc.vim from \\192.168.0.211\samba\vimrc
"""
  function Sd_open_vimrc() abort
    if has('win32') || has('win64')
      if hostname() == "TXLX1090085"
        silent! exe  'edit C:\sd-program\nvim-win64\share\nvim\vimrc.vim'
        silent! exe  'edit ' . g:sd_vim_dir . '/vimrc.vim'
      else
        if filereadable('\\192.168.0.211\samba\vimrc')
          silent! exe  'edit D:\sd-program\nvim-win64\share\nvim\vimrc.vim'
          silent! exe  '%d'
          silent! exe 'read \\192.168.0.211\samba\vimrc'
          silent! exe 'w'
          silent! exe 'w'
          echo "update vimrc"
        else
          call Sd_echo("'\\192.168.0.211\samba\vimrc' not found!")
          silent! exe  'edit ' . g:sd_vim_dir . '/vimrc.vim'
        endif
      endif
    else
      silent! exe  'edit ' . g:sd_vim_dir . '/init.vim'
      echo "open init.vim"
    endif
  endfunction

"""
""" snapshot
"""
  let g:sd_vim_snap_base_dir = $HOME . '/.vim_snap'

  function! Sd_complete_list_snapshot(ArgLead, CmdLine, CursorPos, ...)
    let b:sd_snap_dir = g:sd_vim_snap_base_dir . '/' . expand("%:p:t")
    let myList = readdir(b:sd_snap_dir)
    return filter(myList, 'v:val =~ "^'. a:ArgLead .'"')
  endfunction

  function Sd_create_snap(code) abort
    let snap_dir = g:sd_vim_snap_base_dir . '/' . expand("%:p:t")
    if ! isdirectory(snap_dir)
      call mkdir(snap_dir, "p")
    endif

    if a:code == 0
      let name = input("new snapshot > ", "", "customlist,Sd_complete_list_snapshot")
      if name =~ '^\s*$' || name =~ ".*\<Esc>.*" || name =~ ".*\<C-C>.*"
        return
      endif
      silent exe 'w! ' . snap_dir . '/'. name
      echo expand('%:p:t') . ': create a snap, named - ' . name
    elseif a:code == 2
      silent exe 'w! ' . snap_dir . '/current'
      echo expand('%:p:t') . ': create a snap: "current"'
    else
      let snap_name = 'snap-' . strftime('%Y-%m%d-%H%M-%S', localtime())
      silent exe 'w! ' . snap_dir . '/' . snap_name
      echo 'new quick snapshot: ' . snap_name
    endif
  endfunction

  nnoremap <silent> <leader><leader>sn :call Sd_create_snap(0)<CR>
  nnoremap <silent> <leader>sn :call Sd_create_snap(1)<CR>
  nnoremap <silent> <leader>SN :call Sd_create_snap(2)<CR>

  function Sd_restore_snap(opt) abort
    let b:sd_snap_dir = g:sd_vim_snap_base_dir . '/' . expand("%:p:t")
    if ! isdirectory(b:sd_snap_dir)
      call Sd_echo('no snap for current file')
      return 0
    endif

    let files =  readdir(b:sd_snap_dir)
    if empty(files)
      call Sd_echo('no snap for current file')
      return 0
    endif

    if a:opt == 0
      let restore_num = max(files)
    else
      let restore_num = input("restore from snapshot > ", "", "customlist,Sd_complete_list_snapshot")
      if restore_num =~ '^\s*$' || restore_num =~ ".*\<Esc>.*" || restore_num =~ ".*\<C-C>.*"
        return
      endif
    endif

    if a:opt == 3
      let filetype = &ft
      let file = b:sd_snap_dir . '/'. restore_num
      silent exe 'vs | enew'
      silent normal! ggdG
      silent exe '0read ' . file . ' | setlocal ft=' . filetype
    else
      silent normal! ggdG
      silent exe '0read ' . b:sd_snap_dir . '/'. restore_num
    endif
  endfunction

  nnoremap <silent> <leader>sb :call Sd_restore_snap(1)<CR>
  nnoremap <silent> <leader><leader>sb :call Sd_restore_snap(3)<CR>
  "quick
  nnoremap <silent> <leader>SB :call Sd_restore_snap(0)<CR>

"""
""" vim note
"""
  function Sd_vim_note() abort
    exe 'vs | edit ' . g:sd_template_dir . '/vim-note.txt'
  endfunction
